﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace tetris_data
{
    public class GameData
    {
        private readonly object locker = new object();
        private BlockCell[,] boardData = new BlockCell[20, 10];
        public BlockCell[,] BoardData => boardData;
        public ShapeStruct Next { get; private set; }

        public ShapeStruct Preview { get; private set; }
        public ShapeStruct Current { get; private set; }

        private int level = 1;
        public int Level => level;
        private int removed = 0;
        public int Removed => removed;
        private int score = 0;
        public int Score => score;
        private int levelScore = 0;
        private int ticks = 1000;
        public int Ticks => ticks;
        public Action Removing { get; set; }

        public GameData()
        {

            for (int i = 0; i < 20; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    boardData[i, j] = new BlockCell();
                }
            }
            RandomShape();
        }

        public void RandomShape()
        {
            var baseShapes = Block.Blocks;
            var ran = new Random();
            int index = ran.Next(7);
            var b = baseShapes[index];
            ShapeStruct shape = new ShapeStruct(b);
            if (Current == null)
            {
                Current = shape;
                RandomShape();
            }
            else
            {
                Next = shape;
            }

            var d = ran.Next(4);
            for (int r = 0; r < d; r++)
            {
                Next.ChangeDirection();
            }
        }

        public void ChangeDirection()
        {
            Current.ChangeDirection();
        }

        public bool IsFull()
        {
            if (Current.Top == 0)
            {
                for (var row = 0; row < Current.Height; row++)
                {
                    for (var col = 0; col < Current.Width; col++)
                    {
                        var cell = boardData[Current.Top + row, Current.Left + col];
                        if (this.Current.Cell(row, col) && cell.Visable)
                            return true;
                    }
                }
            }
            return false;
        }

        public void MoveDown()
        {
            lock (locker)
            {

                if (!this.IsBottom())
                {
                    Current.MoveDown();
                }
                else
                {
                    Remove();
                }
            }
        }

        private void RemoveRows()
        {
            if (Preview != null)
            {
                for (var row = 0; row < Preview.Height; row++)
                {
                    for (var col = 0; col < Preview.Width; col++)
                    {
                        if (Preview.Cell(row, col))
                        {
                            var cell = boardData[Preview.Top + row, Preview.Left + col];
                            cell.Visable = true;
                            cell.Color = Preview.Color;
                        }
                    }
                }
            }
            Preview = null;

            int removeCount = 0;
            for (int row = 0; row < 20; row++)
            {
                bool b = true;
                for (int col = 0; col < 10; col++)
                {
                    var cube = BoardData[row, col].Visable;
                    b = b && cube;
                }

                if (b)
                {
                    removed++;
                    removeCount++;
                    for (int ui = row - 1; ui >= 0; ui--)
                    {
                        for (int uj = 0; uj < 10; uj++)
                        {
                            var pre = boardData[ui, uj];
                            boardData[ui + 1, uj].Visable = pre.Visable;
                            boardData[ui + 1, uj].Color = pre.Color;
                        }
                    }
                }
            }

            var tempScore = 0;
            if (removeCount == 1)
                tempScore += 100;
            if (removeCount == 2)
                tempScore += 200;
            if (removeCount == 3)
                tempScore += 400;
            if (removeCount == 4)
                tempScore += 400;

            if (removeCount > 0)
            {
                if (Removing != null)
                {
                    Task.Run(Removing);
                }
            }

            score += tempScore;
            levelScore += tempScore;

            if (levelScore >= 2000)
            {
                if (level < 12)
                {
                    level++;
                    ticks = 1065 - level * 65;
                }
                else
                    level = 1;

                levelScore = 0;
            }
        }

        public bool IsBlock()
        {

            for (var row = 0; row < Current.Height; row++)
            {
                for (var col = 0; col < Current.Width; col++)
                {

                    if (Current.Left > 0 && Current.Cell(row, col)
                            && boardData[Current.Top + row, Current.Left + col - 1].Visable)
                        return true;
                    if ((Current.Left + Current.Width) < 10 && Current.Cell(row, col)
                            && boardData[Current.Top + row, Current.Left + col + 1].Visable)
                        return true;
                }
            }
            return false;
        }

        public void MoveLeft()
        {
            if (!IsBlock())
                Current.MoveLeft();
        }

        public void MoveRight()
        {
            if (!IsBlock())
                Current.MoveRight();
        }

        public void Drop()
        {
            lock (locker)
            {
                int srow = Current.Height;
                int scol = Current.Width;

                int ntop = 20 - srow;
                int curtop = Current.Top;
                for (int _top = curtop; _top < ntop; _top++)
                {
                    for (int row = 0; row < srow; row++)
                    {
                        for (int col = 0; col < scol; col++)
                        {
                            var boardIndex = _top + row + 1;
                            var cubeBaseD = boardData[boardIndex, Current.Left + col];
                            var scube = Current.Cell(row, col);
                            if (cubeBaseD.Visable && scube)
                            {
                                Current.MoveDown(_top - curtop);
                                Remove();
                                return;
                            }
                        }
                    }

                }
                Current.MoveDown(ntop - curtop);

                Remove();
            }
        }

        private void Remove()
        {
            Preview = Current;
            Current = Next;
            RemoveRows();
            RandomShape();
        }

        public void MoveQuickly()
        {
            lock (locker)
            {
                if (!this.IsBottom())
                {
                    Current.MoveDown();
                }
                else
                {
                    Remove();
                }
            }
        }

        bool IsBottom()
        {

            if (Current.Top + Current.Height < 20)
            {
                for (var row = 0; row < Current.Height; row++)
                {
                    for (var col = 0; col < Current.Width; col++)
                    {
                        int br = Current.Top + row + 1;
                        int bc = Current.Left + col;
                        bool b = boardData[br, bc].Visable;

                        if (Current.Cell(row, col))
                            if (b)
                                return true;
                    }
                }
            }
            return Current.Top + Current.Height == 20;
        }
    }
}
